#include "Hook.h"

#include "HookProcManager.h"
#include "HookProcLib.h"


#include SD_TL_PLATFORM_IMPL_INC(.,HookProcManager)

using namespace sd::hp;



void HookBase::innerSetActive( bool iactive )
{
	if( iactive != isActive() )
		if( iactive )
			setHook();
		else
			removeHook();

}
void HookBase::setActive( bool active )
{
	if(active!=isActive())
	{

		HookedProcess& process = HookedProcess::getInstance();
		if(active || !process.getSoftDeactivateMode() )
		{
			if( !active_ && impl_.use_count() && impl_->isActive() )
			{
				setDummyActive( false );

			}else
			{
				if( HookedProcess::getInstance().isLocked() || !HookedProcess::getInstance().getAutolockingMode() )
					innerSetActive( active );
				else
				{
					int retryCounter = 0;
					const int maxTry = 5;

					while(retryCounter < maxTry)
					{
						try
						{	
							tools::locker< HookedProcess > locker(process);
							innerSetActive( active );
							break;
						}	
						catch(const FunctionIsNowCalled& exp)
						{						
							if(++retryCounter >= maxTry)
								throw exp;
							Sleep(200);
						}
					}
				}
			}
		}else
		{
			if( active_ )
			{
				setDummyActive( true );
			}
		}
		active_ = active;
	}

};

bool HookBase::isActive()const
{
	return impl_.use_count() && impl_->isActive() && active_;
}


void HookBase::createImpl()
{
	LibraryRef lib = LibraryManager::get_mutable_instance().getLibrary( library_ );
	impl_ = impl::HookedProcessImplementation::getInstance().CreateHook( *lib.getImpl(), name_, (sd::hp::impl::Callback)getInnerCallbackPtrVirt(), this );
}

void HookBase::lock()
{
	impl_->lock();
}

void HookBase::unlock()
{
	impl_->unlock();
}



void* HookBase::getOriginalPtr()const
{
	return impl_->getCallerOriginalPtr();
}

void HookBase::setHook()
{
	if( !impl_ )
		createImpl();
	{
		bool isUsed = HookedProcess::getInstance().checkLockedThreadsActiveCode(getInnerCallbackPtrVirt()) ;
		if(isUsed)
			throw FunctionIsNowCalled( getName(), getLibrary() );
		impl_->setActive(true);
	}
}

void HookBase::removeHook()
{
	if( impl_ )
		impl_->setActive(false);
}
